// chris 17 Dec 2011
package com.chrishobson.maths;

/**
 * A 3D vector
 * 
 * @author clh
 * 
 */

public class Vector3D {

  /**
   * Creates a vector with all components as 0.
   */
  public Vector3D() {
  }

  /**
   * Creates a 3D vector with the specied components.
   * 
   * @param a_I
   * @param a_J
   * @param a_K
   */
  public Vector3D(double a_I, double a_J, double a_K) {
    SetIJK(a_I, a_J, a_K);
  }

  public void Become(Vector3D a_B) {
    SetIJK(a_B.m_I, a_B.m_J, a_B.m_K);
  }
  
  public double GetI()
  {
    return m_I;
  }
  public double GetJ()
  {
    return m_J;
  }
  public double GetK()
  {
    return m_K;
  }
  
  /**
   * Sets the whole vector in one go.
   * 
   * @param a_I
   * @param a_J
   * @param a_K
   */
  public void SetIJK(double a_I, double a_J, double a_K) {
    m_I = a_I;
    m_J = a_J;
    m_K = a_K;
  }

  /**
   * Computes the dot product with a second vector.
   * 
   * @param a_Vec
   * @return
   */
  public double DotP(Vector3D a_Vec) {
    return m_I * a_Vec.m_I + m_J * a_Vec.m_J + m_K * a_Vec.m_K;
  }

  /**
   * Computes the vector product, returns the result allowing use within a
   * further expression. The result is stored in temp variables before setting
   * a_Res, allowing a_Res to be one of the vectors involved in the cross
   * product if required.
   * 
   * @param a_With
   * @param a_Res
   * @return
   */
  public Vector3D CrossP(Vector3D a_With, Vector3D a_Res) {
    a_Res.SetIJK(m_J * a_With.m_K - m_K * a_With.m_J, m_K * a_With.m_I - m_I
        * a_With.m_K, m_I * a_With.m_J - m_J * a_With.m_I);

    return a_Res;
  }

  /**
   * Returns a new Vector3D which is this x a_With
   * 
   * @param a_With
   *          The other vector
   * @return A new vector
   */
  public Vector3D CrossP(Vector3D a_With) {
    Vector3D l_Ret = new Vector3D();
    return CrossP(a_With, l_Ret);
  }

  /**
   * Makes "this" vector perpendicular to the other Vector by projecting this
   * vector onto the plane of the other Vector.
   * <p>
   * Assume this vector is an X axis vector and a_With is a Y axis then this x
   * a_This gives a Z axis vector. Then Y cross Z will give X which is now
   * perpendicular to the original Y.
   */
  public Vector3D MakePerp(Vector3D a_With) {
    // Cross X (this) with Y (a_With) give Z, stored back in this
    CrossP(a_With, this);

    // Cross Y (a_With) with Z (this) gives X, stored back in this
    return a_With.CrossP(this, this);
  }

  private double m_I, m_J, m_K;
}
